home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / LANG / FORTH / FORTHMAC / OLD / DOCS / !Forthmacs.docs.ascii.RO_impleme < prev    next >
Encoding:
Text File  |  1996-06-15  |  18.5 KB  |  508 lines

  1.  
  2. Forthmacs Implementation
  3. ************************
  4.  
  5. This chapter describes how RISC OS Forthmacs implements the Forth 
  6. virtual machine on the ARM processors.  It assumes that you have a 
  7. fairly good knowledge of conventional Forth implementations; it does 
  8. not attempt to be a tutorial on how Forth works.  
  9.  
  10.  
  11. Dialect
  12. =======
  13.  
  14. RISC OS Forthmacs is an implementation of the Forth-83 standard, with 
  15. a few exceptions.  It is a descendent of the public-domain F83 
  16. implementation by Laxen and Perry and contains most of the F83 
  17. extensions as well as many new ones.  It is compatible with the other 
  18. implementations for Sun-68k, Sparc, Atari, Macintosh and OS-9 
  19. computers.  
  20.  
  21.  
  22. Stack Width and Addressing
  23. ==========================
  24.  
  25. RISC OS Forthmacs deviates from the 83 Standard in the width of the 
  26. stack.  Forth 83 specifies that stack items are 16-bit numbers, and 
  27. that the address space is 64K.  This wastes much of the power of 
  28. modern CPUs and is almost impossible to implement on ARM based 
  29. computers.  
  30.  
  31. In RISC OS Forthmacs, all stack items as well as memory cells are 
  32. 32-bit wide, remember this when writing portable programs.  
  33.  
  34. The address could conceivably grow to 2 to the 32nd power (4 
  35. gigabytes), but this is restricted by the current CPU/MMU versions to 
  36. 16 MBytes.  16-bit or 2-byte memory accesses are not supported any 
  37. longer and must be emulated if necessary.  
  38.  
  39. Note: word accesses are simulated by two byte accesses, take care 
  40. about interrupts occurring here! 
  41.  
  42. The current ARM MMUs don't support non-aligned memory accesses.  NOTE: 
  43. They don't abort or run any exception vector but just do something not 
  44. clearly defined and CPU dependent.  Take care of this, it took me 
  45. hours to find a bug! 
  46.  
  47. All accesses must be one of: 
  48.  
  49. 1) byte-wide access to any address in the address area 
  50.  
  51. 2) cell-wide ( 32-bit ) access to any aligned address 
  52.  
  53.  
  54. Both stacks are pre-decrementing/post-incrementing.  The parameter 
  55. stack holds its top-of-stack in the top-register r10, this allows much 
  56. faster code definitions because of the CPUs load-and-store 
  57. architecture.  
  58.  
  59.  
  60. Register Usage
  61. ==============
  62.  
  63.  
  64.     r7      floating stack pointer  fsp
  65.     r8      instruction pointer     ip
  66.     r9      user area pointer       up
  67.     r10     top-of-stack register   top
  68.     r11     returnstack pointer     rp
  69.     r12     RISC OS frame pointer    fp  never use this!
  70.     r13     stack pointer           sp
  71.     r14     link register           lk
  72.     r15     pc + status + flags     pc
  73.     r15     sr                      sr  hold the flags part of r15
  74.  
  75. Note: In future CPU Versions the internal structure of the pc-register 
  76. might be different, it seems to be better, to imagine pc and status 
  77. register as two registers.  The hardware-errors and the .REGISTERS 
  78. instruction know about this.  
  79.  
  80. r0, r1, r2, r3, r4, r5, and r6 are available for use within code 
  81. definitions.  Don't try to use them for permanent storage, because 
  82. they are used by many code words with no attempt to preserve the 
  83. previous contents.  
  84.  
  85. Registers r7-r11 and r14 can be used within code definitions, but you 
  86. have to save and restore their values at the beginning/end of the 
  87. definition.  r12, r13 and r15 should not be used.  
  88.  
  89.  
  90. Inner <address> Interpreter
  91. ===========================
  92.  
  93. The inner interpreter NEXT is direct threaded, post incrementing.  The 
  94. compilation address of all definitions contain machine code to be 
  95. executed, not a pointer.  Each CODE definition ends with the NEXT 
  96. code, assembled in-line.  The NEXT code is: 
  97.          pc      ip )+   ldr
  98. This means: Load the program-counter PC ( don't affect the CPU status 
  99. ) from the 4-byte cell pointed to by the instruction pointer ip, 
  100. postincrement the instruction-pointer.  So the NEXT is only one CPU 
  101. instruction and very fast.  It is much faster than 
  102.          address  dolink branch
  103.          ...
  104.          pc link mov
  105. constructions because of only one pipeline reload per NEXT. But on the 
  106. other hand, there is definitely a larger overhead for calling 
  107. secondaries.  
  108.  
  109. For discussions about subroutine threaded ( macro extended ) versus 
  110. threaded code implementations see the Forth literature.  Generally, 
  111. macros do bring some advantage in execution speed but give less 
  112. information about the code itself, so debuggers are less useful.  The 
  113. penalty for direct threaded code is hard to predict, it depends very 
  114. much on the type of application.  Something like 50% sounds 
  115. reasonable, so optimising the bottlenecks could bring big advantages.  
  116. The 'runtimer ' utilities might help you doing this.  
  117.  
  118. The assembler macro C; assembles the NEXT instruction and ends 
  119. assembling by END-CODE. A fast conditional next can be done by 
  120.          ...
  121.          r2 0 cmp
  122.          eq next
  123.          ...
  124.  
  125.  
  126. Other Definitions
  127. =================
  128.  
  129. Any word that is not a code definition contains a branch+link 
  130. instruction at the code-field, this makes a relative branch to an 
  131. inline-address and saves the pc+sr to the lk register.  
  132.          runtime-addr    dolink branch
  133. The inline address points to a code fragment (headerless in most 
  134. cases) that implements the run-time action of the word.  The parameter 
  135. field starts just after this branch+link instruction and can be found 
  136. by clearing the flags in the link register like this: 
  137.          r0 lk    th fc000003 #   bic
  138.          r0  get-link
  139.  
  140. The run-time codes may have to push the top-register to the stack, 
  141. save the return pointer to the return-stack and set the instruction or 
  142. stack pointer to the parameter field address.  All standard runtime 
  143. codes (those of variables, constants, colon definitions, user 
  144. variables ...) have been optimized for best cache-hit rates on ARM3/6 
  145. machines.  
  146.  
  147. Note: WORD-TYPE ( cfa -- addr ) finds the address of the words runtime 
  148. code in this implementation.  
  149.  
  150.  
  151. Colon definitions
  152. =================
  153.  
  154. The runtime code: 
  155.     mlabel docolon  assembler
  156.          ip      rp      push
  157.          ip      get-link c;
  158. The body of a Colon Definition starts 4 bytes after the compilation 
  159. address.  The body contains a list of compilation addresses of other 
  160. words.  Each such compilation address is a 32-bit number which is an 
  161. absolute address.  
  162.  
  163.  
  164. Variable
  165. ========
  166.  
  167. The Parameter Field of a VARIABLE contains a 32-bit number which is 
  168. the value of the variable.  The runtime code: 
  169.     mlabel dovariable  assembler
  170.          top     sp      push
  171.          top     get-link c;
  172.  
  173.  
  174. Constants
  175. =========
  176.  
  177. The Parameter Field of a CONSTANT contains the 32-bit value of the 
  178. constant.  The runtime code: 
  179.     mlabel doconstant  assembler
  180.          top     sp      push
  181.          r0      get-link
  182.          top     r0 )    ldr c;
  183.  
  184.  
  185. User Variables
  186. ==============
  187.  
  188. The value of a USER variable is stored in the USER area as a 32-bit 
  189. number.  The Parameter Field of a user variable contains a 32-bit 
  190. offset into the user area of the current task.  r8 contains the base 
  191. address of the current user area.  r8 is symbolically defined as UP in 
  192. the assembler.  The runtime code: 
  193.     mlabel douser  assembler
  194.          top     sp      push
  195.          r0      get-link
  196.          r0      r0 )    ldr
  197.          top     r0      up add c;
  198.  
  199.  
  200. Deferred words
  201. ==============
  202.  
  203. The compilation address of the word to be executed by a DEFER word is 
  204. stored as a 32-bit absolute address in the USER area.  The Parameter 
  205. Field of a deferred word contains a 32-bit number which is an offset 
  206. into the user area of the current task.  The runtime code: 
  207.     mlabel dodefer  assembler
  208.          r0      get-link
  209.          r0      r0 )    ldr
  210.          pc      r0      up  ib ldr end-code
  211. The last line holds a somewhat optimized NEXT instruction, it means: 
  212. Load the pc from the address in the user area with the offset r0.  
  213.  
  214.  
  215. ;code
  216. =====
  217.  
  218. The compilation address of a word created by a CREATE ...  ;CODE data 
  219. type construction contains the standard branch+link instruction that 
  220. branches to the runtime code.  
  221.  
  222. The runtime code is defined by the programmer in the ;CODE part of the 
  223. definition.  At first the ;CODE instruction assembles 
  224.          top     sp      push
  225.          top     get-link
  226. before the programmers code.  This is mainly for convenience, so the 
  227. top is already saved to the stack and points to the parameter field.  
  228. The programmer might do '-2 cells allot ' to forget this for speed 
  229. optimized code.  
  230.  
  231.  
  232. does>
  233. =====
  234.  
  235.  
  236.     mlabel dodoes  assembler
  237.          ip      rp      push
  238.          ip      get-link c;
  239. The runtime code is defined by the programmer in the DOES> part of the 
  240. definition.  Before branching to the dodoes code, the does> 
  241. instruction assembles 
  242.          top     sp      push
  243.          top     lk      th fc000003 # bic
  244. to get the parameter field address.  
  245.  
  246.  
  247. local variables
  248. ===============
  249.  
  250. RISC OS Forthmacs has built in ANS Forth conforming local variables 
  251. spending their lifetime on the return-stack in stack-frames.  The 
  252. stack-frames are linked via a USER variable LOCAL-FRAME which is also 
  253. used to locate a local variables value.  The frame structure is like: 
  254.     | cfa:frame>   | old-frame     | old-rs        | loc   | loc   | .........
  255. with cfa:pop-frame on top of the return-stack.  pop-frame removes the 
  256. current frame and switches to the last frame.  
  257.     headerless code pop-frame \ this routine is pushed on return stack by push-locals
  258.          here-t /token-t + token,-t
  259.         r0 rp 2    rp ia    ldm
  260.         r0    'user local-frame str
  261.         ip    rp    pop c;
  262.     
  263. The local variables are accessed using (loc) followed by an stack 
  264. frame index.  
  265.     code (loc)    \ ( -- n )  runtime-code of any local
  266.         r0    'user local-frame ldr
  267.         r1    ip )+    ldr
  268.         top    sp    push
  269.         top    r0 r1 2 #asl db ldr c;
  270.  
  271. Note: The disassembler can NOT know the local variables names, so it 
  272. assumes names like V0 V1 ... .  
  273.  
  274.  
  275. Vocabularies
  276. ============
  277.  
  278. Each VOCABULARY has #THREADS ( currently 16 ) 32-bit pointers which 
  279. are called "threads".  A thread is the head of a linked list of words.  
  280. A hashing function selects which of the 16 linked lists a particular 
  281. word belongs to.  The threads are stored in the USER area.  The 
  282. Parameter Field of a VOCABULARY contains the 32-bit offset of the 
  283. threads in the USER area, followed by the vocabulary-link, a 32-bit 
  284. pointer to the previous VOCABULARY. The runtime high-level code is: 
  285.          does> body> context token!
  286.  
  287.  
  288. Tokens
  289. ======
  290.  
  291. Within the body of a colon definition, calls to other Forth words are 
  292. compiled as the 32-bit absolute compilation address of those words.  
  293. These tokens have a corresponding bit in the relocation table.  
  294.  
  295.  
  296. Branching
  297. =========
  298.  
  299. Branch targets are offsets relative to the location that contains the 
  300. branch offset.  They are stored as 32-bit twos-complement numbers 
  301. representing the number of bytes between the offset location and the 
  302. branch target.  For example, a branch to the following location could 
  303. be compiled with: 
  304.  
  305.          postpone branch   4 ,
  306.  
  307.  
  308. Doubles
  309. =======
  310.  
  311. RISC OS Forthmacs versions newer than 1.83 have full double number 
  312. support, all conversion tools CONVERT, NUMBER?, D. use doubles, the 
  313. 'scaling' words */ */MOD UM/MOD use double intermediate results.  
  314.  
  315. Also the text-interpreter and compiler accept literals as doubles when 
  316. there is a period in it.  
  317.          : test 1234. d. ;
  318. 1234.  is a double number and D. displays it.  
  319.  
  320. This could only be achieved with changing stack effects in a number of 
  321. words.  So these new RISC OS Forthmacs versions are no longer 
  322. compatible when these words are used.  The lib.compatible tool does 
  323. NOT cover these changes.  
  324.  
  325. The advantage of the new stack behaviour is it's ANS compliancy and 
  326. the improved arithmetic capabilities.  
  327.  
  328.  
  329. Header format - # of bytes in parentheses
  330. =========================================
  331.  
  332. Source Field (4), Link Field (4), Name Field (n), Padding (0 to 3), 
  333. Flags (1), Code Field (4), Parameter Field (n).  
  334.  
  335. As all addresses need to be, the Link Field, Name Field, and Code 
  336. Field are all aligned.  
  337.  
  338. Links point to links ( NOT to Name Fields, as in FIG Forth! ) 
  339.  
  340. The name field is a normal Forth packed string.  (Many Forth 
  341. implementations set the high bit in the first and last characters of 
  342. the name field; RISC OS Forthmacs does not).  
  343.  
  344. Name Field: length-byte, 0-31 character name.  
  345.  
  346.  
  347.  
  348. Vocabulary Format
  349. =================
  350.  
  351. Vocabularies have #THREADS- way hashing.  This means that each 
  352. vocabulary has 16 separate linked lists of words.  Before searching a 
  353. vocabulary, a hashing function is applied to the name to be located.  
  354. The hashing function selects one of the 16 linked lists to search.  
  355.  
  356. The hashing function is very simple.  The lower 4 bits of the first 
  357. character in the name (the first name character, not the length byte) 
  358. are interpreted as a number from 0 to 15, selecting a linked list.  
  359.  
  360. Vocabularies are not chained to one another.  Search order is 
  361. implemented using the ALSO / ONLY scheme.  Each vocabulary thread is 
  362. terminated with a special link field in the final word.  The special 
  363. link address is the address of the origin of the Forth system (which 
  364. may change from session to session due to the relocation that the 
  365. operating system applies when loading and executing the Forth system.  
  366.  
  367. The parameter field for a vocabulary looks like: 
  368.  
  369. User number (/cell), Voc-link (/cell) 
  370.  
  371. The user number selects the place in the user area where the head of 
  372. list pointers for the 16 vocabulary threads are stored.  Each 
  373. vocabulary requires 16 CELLS bytes of user area storage for these 16 
  374. threads.  The values stored in the user area are the Link field 
  375. Addresses for the top word in each thread.  
  376.  
  377.  
  378. Relocation
  379. ==========
  380.  
  381. In the RISC OS environment all programs of the absolute type are 
  382. loaded at $8000 and executed from there.  So on first sight the 
  383. relocation table doesn't make much sense in this version.  
  384.  
  385. But the relocation table can be used for target/meta-compiling or for 
  386. relocating code during run-time.  This is necessary for producing 
  387. turnkey applications with an 'Application Stripper', use of the 
  388. application stripper requires strict adherence to the rules of 
  389. relocatability.  
  390.  
  391. If the program is not relocatable, then a file saved with SAVE-FORTH 
  392. will work only if it is later executed at the same address where it 
  393. was executing when it was saved.  If saved with SAVE-TURNKEY, a 
  394. program that is not relocatable will not work at all, regardless of 
  395. the address where it is later executed.  Consequently, use of the 
  396. application stripper requires strict adherence to the rules of 
  397. relocatability.  
  398.  
  399. In most cases, the relocation bitmap is maintained automatically, 
  400. without requiring any special effort on the part of the programmer.  
  401. However, there are some cases where the programmer must take explicit 
  402. actions to ensure that the program is relocatable.  
  403.  
  404. The executable file contains a relocation list used to identify the 
  405. locations in the program's binary image which contain absolute 
  406. addresses.  When the program is loaded, each of these locations is 
  407. modified by adding the starting address of the program to the number 
  408. contained in that location.  Only 32-bit numbers may be so modified.  
  409.  
  410. While RISC OS Forthmacs is running, it maintains its own relocation 
  411. table, identifying those locations in the Forth dictionary which must 
  412. be relocated during COLD-CODE. Each bit in the map represents the 
  413. address of one aligned location.  This relocation table is completely 
  414. different from the standard RISC OS relocation tables, it is only used 
  415. from within RISC OS Forthmacs.  
  416.  
  417. In order for this to work properly, the programmer must be careful to 
  418. use TOKEN, A, LINK, TOKEN!, A! or LINK! to store an address or token 
  419. in the dictionary, all six set the relocation flags.  
  420.  
  421. Addresses may be stored into VARIABLEs with ! (without requiring the 
  422. use of TOKEN! ) if the VARIABLE is re-initialized every time that the 
  423. application is started.  TOKEN! is only necessary if the VARIABLEs 
  424. value must be set before SAVE-FORTH is executed, and then is used when 
  425. the saved application is later invoked, without being re-initialized 
  426. by the application's initialization code.  
  427.  
  428. If , or ! is used instead, the address will not be properly relocated 
  429. if SAVE-FORTH has been used to write the dictionary image to an 
  430. executable file.  
  431.  
  432. Note: The lib/checkrel.fth program can help you catch relocation 
  433. problems in your applications.  It should be loaded before you load 
  434. your application, and will warn you if your application does things 
  435. that may not be relocatable.  After you have fixed the relocation 
  436. problems, you can load your application without lib/checkrel.fth .  
  437. Also .BUFFERS 
  438.  
  439.  
  440. See: .BUFFERS .POINTERS TOKEN! TOKEN, A! A, LINK! LINK, 
  441. SET-RELOCATION-BIT RELOCATION-MAP 
  442.  
  443.  
  444. Program header
  445. ==============
  446.  
  447. The header of the executable binary image looks like this: 
  448.  
  449.  h_magic   (  0)    \ Magic Number
  450.  h_tlen    (  4)    \ length of text (code)
  451.  h_dlen    (  8)    \ length of initialised data
  452.  h_blen    (  c)    \ length of BSS unitialised data
  453.  h_slen    (  10)   \ length of symbol table
  454.  h_entry   (  14)   \ Entry address
  455.  h_trlen   (  18)   \ Text Relocation Table length
  456.  h_drlen   (  1c)   \ Data Relocation Table length
  457.  
  458. the magic number is the branch+link instruction just behind this 
  459. header.  Note: this header might be changed with future releases 
  460. according to Acorns executable binary code standard.  
  461.  
  462.  
  463. Heap memory
  464. ===========
  465.  
  466. RISC OS Forthmacs is loaded to $8000 and will have as much memory 
  467. available as was defined by 'WimpSlot' .  
  468.  
  469. The MAIN-TASKs user area immediately follows the first instructions at 
  470. $8050.  
  471.  
  472. $600 byte will be allocated in module-heap, it will hold the ENV-AREA, 
  473. the command-line area, the INTERRUPT-CODE giving GET-TICKS plus all 
  474. handlers used by shelled programs.  
  475.  
  476. The implementation of the dynamic memory manager has changed in 
  477. Version 3.1-2.00.  From now on the dictionary and the heap share the 
  478. same memory area, the dictionary grows from lower addresses and the 
  479. heap can be as large as the area between the stacks and HERE. 
  480.  
  481. Note: Of course you may install another memory manager or add more 
  482. heaps.  
  483.  
  484.  
  485. Dictionary memory
  486. =================
  487.  
  488. At the top of the dictionary are both stacks defined by RP0 - RS-SIZE 
  489. and SP0 - PS-SIZE and the TIB, below this are MBytes of free memory 
  490. (well, hopefully).  HERE marks the end of the allocated dictionary, 
  491. classically PAD is HERE plus something.  
  492.  
  493. RISC OS Forthmacs knows about two dictionary areas, the RESIDENT 
  494. (which is the dictionary you know in all implementations) and the 
  495. TRANSIENT. The transient dictionary is in the heap memory, definitions 
  496. defined here won't use dictionary space in the target application.  So 
  497. it might be useful to do: 
  498.     transient
  499.       fload assembler
  500.       fload debugger
  501.     resident
  502.       fload myapplication
  503. Now the debugger and assembler will be in transient address space.  To 
  504. remove all links, pointers etc.  into the transient address space use 
  505. DISPOSE, it will do this for you.  .DISPOSE will also give some 
  506. informations what is removed.  
  507.  
  508.